package com.ybear.mvp.handler;

import android.os.Build;
import android.os.Looper;
import android.os.Message;
import android.util.Printer;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.util.Consumer;

import java.lang.ref.WeakReference;
import java.util.concurrent.Callable;

public final class DelegateHandler implements Handler {
    @NonNull
    private final HandlerImpl mImpl;

    public DelegateHandler(HandlerCallback callback) {
        mImpl = new HandlerImpl( Looper.getMainLooper(), callback );
    }

    public static DelegateHandler create(HandlerCallback callback) {
        return new DelegateHandler( callback );
    }

    @Override
    public android.os.Handler getOsHandler() { return mImpl; }

    @Override
    public Handler getHandler() { return this; }

    @Override
    public <T> boolean postAsync(Callable<T> executeCall, Consumer<T> resultCall, boolean postResult) {
        return mImpl.postAsync( executeCall, resultCall, postResult );
    }

    @Override
    public <T> boolean postAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall, boolean postResult) {
        return mImpl.postAsync( executeCall, resultCall, postResult );
    }

    @Override
    public <T> boolean postDelayedAsync(Callable<T> executeCall, Consumer<T> resultCall, boolean postResult, long delayMillis) {
        return mImpl.postDelayedAsync( executeCall, resultCall, postResult, delayMillis );
    }

    @Override
    public <T> boolean postDelayedAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall, boolean postResult, long delayMillis) {
        return mImpl.postDelayedAsync( executeCall, resultCall, postResult, delayMillis );
    }

    @Override
    public <T> boolean postAsync(Callable<T> executeCall, Consumer<T> resultCall, boolean postResult, long delayMillis) {
        return mImpl.postAsync( executeCall, resultCall, postResult, delayMillis );
    }

    @Override
    public <T> boolean postAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall, boolean postResult, long delayMillis) {
        return mImpl.postAsync( executeCall, resultCall, postResult, delayMillis );
    }

    @Override
    public <T> boolean postAsync(Callable<T> executeCall, Consumer<T> resultCall) {
        return mImpl.postAsync( executeCall, resultCall );
    }

    @Override
    public <T> boolean postAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall) {
        return mImpl.postAsync( executeCall, resultCall );
    }

    @Override
    public <T> boolean postDelayedAsync(Callable<T> executeCall, Consumer<T> resultCall, long delayMillis) {
        return mImpl.postDelayedAsync( executeCall, resultCall, delayMillis );
    }

    @Override
    public <T> boolean postDelayedAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall, long delayMillis) {
        return mImpl.postDelayedAsync( executeCall, resultCall, delayMillis );
    }

    @Override
    public <T> boolean postAsync(Callable<T> executeCall, Consumer<T> resultCall, long delayMillis) {
        return mImpl.postAsync( executeCall, resultCall, delayMillis );
    }

    @Override
    public <T> boolean postAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall, long delayMillis) {
        return mImpl.postAsync( executeCall, resultCall, delayMillis );
    }

    @Override
    public <T> boolean postAsync(Runnable executeCall) {
        return mImpl.postAsync( executeCall );
    }

    @Override
    public <T> boolean postDelayedAsync(Runnable executeCall, long delayMillis) {
        return mImpl.postDelayedAsync( executeCall, delayMillis );
    }

    @Override
    public <T> boolean postAsync(Runnable executeCall, long delayMillis) {
        return mImpl.postAsync( executeCall, delayMillis );
    }

    @Override
    public boolean post(Runnable r) {
        return mImpl.post( r );
    }
    @Override
    public boolean post(Runnable r, long delayMillis) {
        return delayMillis > 0 ? mImpl.postDelayed( r, delayMillis ) : mImpl.post( r );
    }
    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    public boolean post(Runnable r, @Nullable Object token, long delayMillis) {
        return mImpl.postDelayed( r, token, delayMillis );
    }
    @Override
    public boolean postDelayed(Runnable r, long delayMillis) {
        return mImpl.postDelayed( r, delayMillis );
    }
    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    public boolean postDelayed(@NonNull Runnable r, @Nullable Object token, long delayMillis) {
        return mImpl.postDelayed( r, token, delayMillis );
    }
    @Override
    public boolean postAtFrontOfQueue(@NonNull Runnable r) {
        return mImpl.postAtFrontOfQueue( r );
    }
    @Override
    public boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
        return mImpl.postAtTime( r, uptimeMillis );
    }
    @Override
    public boolean postAtTime(@NonNull Runnable r, @Nullable Object token, long uptimeMillis) {
        return mImpl.postAtTime( r, token, uptimeMillis );
    }

    @Override
    public boolean sendMessage(@NonNull Message msg) {
        return mImpl.sendMessage( msg );
    }
    @Override
    public boolean sendEmptyMessage(int what) {
        return mImpl.sendEmptyMessage( what );
    }
    @Override
    public boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        return mImpl.sendEmptyMessageDelayed( what, delayMillis );
    }
    @Override
    public boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        return mImpl.sendEmptyMessageAtTime( what, uptimeMillis );
    }
    @Override
    public boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        return mImpl.sendMessageDelayed( msg, delayMillis );
    }
    @Override
    public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        return mImpl.sendMessageAtTime( msg, uptimeMillis );
    }
    @Override
    public boolean sendMessageAtFrontOfQueue(@NonNull Message msg) {
        return mImpl.sendMessageAtFrontOfQueue( msg );
    }

    @Override
    public boolean hasMessages(int what) {
        return mImpl.hasMessages( what );
    }
    @Override
    public boolean hasMessages(int what, @Nullable Object object) {
        return mImpl.hasMessages( what, object );
    }

    @Override
    public void removeMessages(int what) {
        mImpl.removeMessages( what );
    }
    @Override
    public void removeMessages(int what, @Nullable Object object) {
        mImpl.removeMessages( what, object );
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    @Override
    public boolean hasCallbacks(@NonNull Runnable r) {
        return mImpl.hasCallbacks( r );
    }
    @Override
    public void removeCallbacks(@NonNull Runnable r) {
        mImpl.removeCallbacks( r );
    }
    @Override
    public void removeCallbacks(@NonNull Runnable r, @Nullable Object token) {
        mImpl.removeCallbacks( r, token );
    }

    @Override
    public void removeCallbacksAndMessages(@Nullable Object token) {
        mImpl.removeCallbacksAndMessages( token );
    }

    @NonNull
    @Override
    public Message obtainMessage() {
        return mImpl.obtainMessage();
    }
    @NonNull
    @Override
    public Message obtainMessage(int what) {
        return mImpl.obtainMessage( what );
    }
    @NonNull
    @Override
    public Message obtainMessage(int what, @Nullable Object obj) {
        return mImpl.obtainMessage( what, obj );
    }
    @NonNull
    @Override
    public Message obtainMessage(int what, int arg1, int arg2) {
        return mImpl.obtainMessage( what, arg1, arg2 );
    }
    @NonNull
    @Override
    public Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj) {
        return mImpl.obtainMessage( what, arg1, arg2, obj );
    }

    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    public android.os.Handler createAsyncForOs(@NonNull Looper looper) {
        return android.os.Handler.createAsync( looper );
    }
    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    public android.os.Handler createAsyncForOs(@NonNull Looper looper,
                                               @NonNull android.os.Handler.Callback callback) {
        return android.os.Handler.createAsync( looper, callback );
    }

//    @RequiresApi(api = Build.VERSION_CODES.P)
//    @Override
//    public Handler createAsync(@NonNull Looper looper) {
//        return (DelegateHandler) android.os.Handler.createAsync( looper );
//    }
//
//    @RequiresApi(api = Build.VERSION_CODES.P)
//    @Override
//    public Handler createAsync(@NonNull Looper looper, @NonNull Callback callback) {
//        return (Handler) android.os.Handler.createAsync( looper, callback );
//    }

    @Override
    public void dump(@NonNull Printer pw, @NonNull String prefix) {
        mImpl.dump( pw, prefix );
    }

    @NonNull
    @Override
    public Looper getLooper() {
        return mImpl.getLooper();
    }
}
